package demoMod.anm2editor.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import demoMod.anm2editor.fonts.FontKeys;
import demoMod.anm2editor.interfaces.ReloadStringsSubscriber;
import demoMod.anm2editor.localization.LocalizedStrings;
import demoMod.anm2editor.model.*;
import demoMod.gdxform.abstracts.Container;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.Element;
import demoMod.gdxform.interfaces.KeyboardEventSubscriber;
import demoMod.gdxform.interfaces.MouseEventSubscriber;
import demoMod.gdxform.ui.*;

import java.util.ArrayList;
import java.util.List;

public class AnimationPane extends Container<Element> implements MouseEventSubscriber, KeyboardEventSubscriber, ReloadStringsSubscriber {
    public static final String ID = "AnimationPane";
    private final AnimationList animationList = new AnimationList();
    private boolean mouseDown = false;
    private final GScrollPane scrollPane;
    private final GLabel label;

    public AnimationPane() {
        setWidth(Gdx.graphics.getWidth() * 0.1F);
        setHeight(Gdx.graphics.getHeight() * 0.2F);
        setX(0.9F * Gdx.graphics.getWidth());
        setY(20);
        setBackground(Color.WHITE.cpy());
        setBackground(Color.GRAY.cpy());
        setId(ID);
        scrollPane = new GScrollPane(0, 20, getWidth(), getHeight() - 40.0F, getWidth() * 2, getHeight() * 2);
        scrollPane.setBackground(Color.WHITE.cpy());
        scrollPane.setBackground(Color.DARK_GRAY.cpy());
        GVScrollBar vScrollBar = new GVScrollBar(0, 0, 10, getHeight());
        scrollPane.setVScrollBar(vScrollBar);
        addElement(scrollPane);
        animationList.setCellHeight(((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
        animationList.setMaxSelectedItems(1);
        scrollPane.addElement(animationList);
        setBorderWidth(1);
        setBorder(Color.LIGHT_GRAY.cpy());
        label = new GLabel(5.0F, getHeight() - 10.0F, getWidth(), 20.0F, FontHelper.getFont(FontKeys.SIM_HEI_16));
        List<String> strings = LocalizedStrings.getStrings(ID);
        label.setText(strings.get(6));
        addElement(label);
        LocalizedStrings.subscribe(this);
    }

    public AnimationList getAnimationList() {
        return animationList;
    }

    public void addAnimation(Animation animation) {
        AnimationItem animationItem = new AnimationItem(getWidth(), animationList.getCellHeight(), animation, FontHelper.getFont(FontKeys.SIM_HEI_16));
        animationItem.setId(animation.getName());
        animationList.addItem(animationItem);
        if (animation.isDefaultAnimation()) {
            animationList.setSelected(animationList.indexOf(animationItem), true);
        }
    }

    public void addAnimation(int index, Animation animation) {
        AnimationItem animationItem = new AnimationItem(getWidth(), animationList.getCellHeight(), animation, FontHelper.getFont(FontKeys.SIM_HEI_16));
        animationItem.setId(animation.getName());
        animationList.addItem(index, animationItem);
        if (animation.isDefaultAnimation()) {
            animationList.setSelected(animationList.indexOf(animationItem), true);
        }
    }

    public void removeAnimation(Animation animation) {
        for (GList.ListCellRenderer<AnimationItem> cellRenderer : animationList.getElements()) {
            if (cellRenderer.getElements().get(0).getAnimation() == animation) {
                cellRenderer.dispose();
                animationList.removeItem(cellRenderer.getElements().get(0));
                break;
            }
        }
    }

    public void clear() {
        for (Element element : animationList.getElements()) {
            element.dispose();
        }
        animationList.clear();
        scrollPane.getVScrollBar().setProgress(0);
    }

    public void selectAnimation(int index, boolean selected) {
        animationList.setSelected(index, selected);
    }

    @Override
    public boolean keyDown(int keyCode) {
        return false;
    }

    @Override
    public boolean keyUp(int keyCode) {
        return false;
    }

    @Override
    public boolean keyTyped(char key) {
        return false;
    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        mouseDown = (float)screenX >= this.getX(true) && (float)screenX <= this.getX(true) + this.getWidth() && (float)(Gdx.graphics.getHeight() - screenY) >= this.getY(true) && (float)(Gdx.graphics.getHeight() - screenY) <= this.getY(true) + this.getHeight();
        if (mouseDown) {
            FormManager.getInstance().moveToTop(this);
            List<Element> elements = this.getElements();
            for(int i = elements.size() - 1; i >= 0; --i) {
                Element element = elements.get(i);
                if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).clickDown(screenX, screenY, button)) {
                    return true;
                }
            }
            FormManager.getInstance().getEventHooks().setCurrentFocusedElement(this);
            if (button == Input.Buttons.RIGHT) {
                List<String> strings = LocalizedStrings.getStrings(ID);
                GMenuList menuList = new GMenuList();
                menuList.setWidth(150.0F);
                menuList.setX(screenX - menuList.getWidth());
                menuList.setY(Gdx.graphics.getHeight() - screenY);
                GMenuItem newAnimation = new GMenuItem(menuList.getWidth(), menuList.getMenuItemHeight(), strings.get(0) + "...", FontHelper.getFont(FontKeys.SIM_HEI_14)) {
                    @Override
                    public void onClick() {
                        TextInputWindow textInputWindow = new TextInputWindow(strings.get(1), "", FontHelper.getFont(FontKeys.SIM_HEI_14));
                        textInputWindow.setConfirmCallback(name -> {
                            List<GCheckBox> options = new ArrayList<>();
                            GCheckBox loop = new GCheckBox(0, 0, 16, 16, FontHelper.getFont(FontKeys.SIM_HEI_14));
                            loop.setText(strings.get(2));
                            GCheckBox defaultAnimation = new GCheckBox(0, 0, 16, 16, FontHelper.getFont(FontKeys.SIM_HEI_14));
                            defaultAnimation.setText(strings.get(3));
                            options.add(loop);
                            options.add(defaultAnimation);
                            CheckBoxWindow checkBoxWindow = new CheckBoxWindow(strings.get(4), options, FontHelper.getFont(FontKeys.SIM_HEI_14));
                            checkBoxWindow.setConfirmCallback(checkBoxList -> {
                                Animation animation = new Animation();
                                animation.setName(name);
                                if (checkBoxList.get(1).getState() == 1) {
                                    for (Animation animation1 : Project.currentProject.getAnimations()) {
                                        animation1.setDefaultAnimation(false);
                                    }
                                    animation.setDefaultAnimation(true);
                                }
                                animation.setLoop(checkBoxList.get(0).getState() == 1);
                                Project.currentProject.getAnimations().add(animation);
                                AnimationItem itemToAdd = new AnimationItem(getWidth(), animationList.getCellHeight(), animation, FontHelper.getFont(FontKeys.SIM_HEI_16));
                                itemToAdd.setId(animation.getName());
                                animationList.addItem(-1, itemToAdd);
                                List<TrackContent> trackContents = new ArrayList<>();
                                for (Track track : Project.currentProject.getTracks()) {
                                    TrackContent content = new TrackContent().setKeyFrames(new ArrayList<>());
                                    track.addContent(animation.getName(), content);
                                    trackContents.add(content);
                                }
                                Project.currentProject.setCurrentAnimation(animation);
                                ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).clearTrack();
                                ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).clearTrack();
                                for (Track track : Project.currentProject.getTracks()) {
                                    ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).addTrack(animation.getName(), track);
                                    ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).addTrack(track);
                                }
                                for (GList.ListCellRenderer<AnimationItem> cellRenderer : animationList.getElements()) {
                                    animationList.setSelected(animationList.indexOf(cellRenderer.getElements().get(0)), cellRenderer.getElements().get(0).getAnimation() == animation);
                                }
                                for (Event event : Project.currentProject.getEvents()) {
                                    event.getUsages().put(animation.getName(), new ArrayList<>());
                                }
                                if (Project.currentProject.getAnimations().size() * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight() > scrollPane.getPlainHeight()) {
                                    scrollPane.setPlainHeight(scrollPane.getPlainHeight() + 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
                                }
                                Operation operation = new Operation() {
                                    @Override
                                    public void undo() {
                                        Project.currentProject.getAnimations().remove(animation);
                                        ((AnimationPane)FormManager.getInstance().getContainerById(AnimationPane.ID)).removeAnimation(animation);
                                        for (Track track : Project.currentProject.getTracks()) {
                                            track.removeContent(animation.getName());
                                        }
                                        Animation currentAnimation = Project.currentProject.getCurrentAnimation();
                                        ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).clearTrack();
                                        ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).clearTrack();
                                        if (currentAnimation != null) {
                                            for (Track track : Project.currentProject.getTracks()) {
                                                ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).addTrack(currentAnimation.getName(), track);
                                                ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).addTrack(track);
                                            }
                                        }
                                        for (Event event : Project.currentProject.getEvents()) {
                                            event.getUsages().remove(animation.getName());
                                        }
                                        GScrollPane scrollPane = ((AnimationPane) FormManager.getInstance().getContainerById(AnimationPane.ID)).getScrollPane();
                                        if (scrollPane.getPlainHeight() - Project.currentProject.getAnimations().size() > 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight()) {
                                            float plainHeight = scrollPane.getPlainHeight() - 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight();
                                            if (FormManager.getInstance().getContainerById(AnimationPane.ID).getHeight() * 2 > plainHeight) {
                                                plainHeight = FormManager.getInstance().getContainerById(AnimationPane.ID).getHeight() * 2;
                                            }
                                            scrollPane.setPlainHeight(plainHeight);
                                        }
                                    }

                                    @Override
                                    public void redo() {
                                        Project.currentProject.getAnimations().add(animation);
                                        animationList.addItem(-1, itemToAdd);
                                        if (animation.isDefaultAnimation()) {
                                            animationList.setSelected(0, true);
                                        }
                                        int i = 0;
                                        for (Track track : Project.currentProject.getTracks()) {
                                            track.addContent(animation.getName(), trackContents.get(i));
                                            i++;
                                        }
                                        Project.currentProject.setCurrentAnimation(animation);
                                        ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).clearTrack();
                                        ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).clearTrack();
                                        for (Track track : Project.currentProject.getTracks()) {
                                            ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).addTrack(animation.getName(), track);
                                            ((TrackPane) FormManager.getInstance().getContainerById(TrackPane.ID)).addTrack(track);
                                        }
                                        GScrollPane scrollPane = ((AnimationPane) FormManager.getInstance().getContainerById(AnimationPane.ID)).getScrollPane();
                                        if (Project.currentProject.getAnimations().size() * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight() > scrollPane.getPlainHeight()) {
                                            scrollPane.setPlainHeight(scrollPane.getPlainHeight() + 3 * ((Timeline) FormManager.getInstance().getContainerById(Timeline.ID)).getTrackHeight());
                                        }
                                        for (Event event : Project.currentProject.getEvents()) {
                                            event.getUsages().put(animation.getName(), new ArrayList<>());
                                        }
                                    }
                                };
                                operation.setName(strings.get(5));
                                ((HistoryPanel) FormManager.getInstance().getContainerById(HistoryPanel.ID)).addOperation(operation);
                            });
                        });
                    }
                };
                newAnimation.setSplitLine(false);
                menuList.addElement(newAnimation);
                FormManager.getInstance().addContainer(menuList);
                FormManager.getInstance().moveToTop(menuList);
            }
            return true;
        }
        return false;
    }

    public GScrollPane getScrollPane() {
        return scrollPane;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        if (!this.mouseDown) return false;
        this.mouseDown = false;
        List<Element> elements = this.getElements();

        for(int i = elements.size() - 1; i >= 0; --i) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber && ((MouseEventSubscriber)element).clickUp(screenX, screenY, button)) {
                break;
            }
        }
        return true;
    }

    @Override
    public boolean mouseDragged(int screenX, int screenY) {
        List<Element> elements = getElements();
        for (int i=elements.size() - 1;i >= 0;i--) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) element).mouseDragged(screenX, screenY)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        if (!this.visible()) return false;
        List<Element> elements = getElements();
        for (int i=elements.size() - 1;i >= 0;i--) {
            Element element = elements.get(i);
            if (element instanceof MouseEventSubscriber) {
                if (((MouseEventSubscriber) element).scrolled(amount)) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public boolean moveToElementBorder(Element element) {
        return false;
    }

    @Override
    public void onReloadStrings() {
        List<String> strings = LocalizedStrings.getStrings(ID);
        label.setText(strings.get(6));
    }
}
